#pragma once
#include "ZuiLib.h"
#include "support/network/ZHttpClient.h"
#include "LRefObject.h"

namespace ZuiLib {

class LHttpResponce :public LRefObject<ZHttpResponse>
{
public:
	int isSucceed(LuaFuncState& L)
	{
		return L.lreturn(pThis->isSucceed());
	}

	int getData(LuaFuncState& L)
	{
		std::vector<char>* data = pThis->getResponseData();
		return L.lreturn(L.newString(data->data(), data->size()));
	}

	int getHeader(LuaFuncState& L)
	{
		std::vector<char>* data = pThis->getResponseHeader();
		return L.lreturn(L.newString(data->data(), data->size()));
	}

	int getCode(LuaFuncState& L)
	{
		return L.lreturn(pThis->getResponseCode());
	}

	int getError(LuaFuncState& L)
	{
		return L.lreturn(pThis->getErrorBuffer());
	}

	BEGIN_MAP_FUNC(LHttpResponce)
	DECLARE_FUNC(isSucceed),
	DECLARE_FUNC(getData),
	DECLARE_FUNC(getHeader),
	DECLARE_FUNC(getCode),
	DECLARE_FUNC(getError),
	END_MAP_FUNC
};


class LResponseCallback :public ZSchedulerBase
{
public:
	LResponseCallback() :m_callId(0) {}

	LResponseCallback(LuaObject func)
	{
		m_callId = saveCallbackFunction(func);
	}

	~LResponseCallback() {
		if (IsMainThread())
		{
			LuaState* L = ZScriptEngine::Instance()->GetLuaState();
			if (L)
				removeCallbackFunction(L, m_callId);
		}
	}

	void OnResponce(ZHttpClient* client, ZHttpResponse* response)
	{
		LuaState* L = ZScriptEngine::Instance()->GetLuaState();
		try {
			LuaFunction func = getCallbackFunction(L, m_callId);
			if (func.isValid())
			{
				func(LuaClass<ZHttpResponse>::cToLua(L,response));
			}
		}
		catch (LuaException e)
		{
			LOG(LS_LUAERROR) << e.what();
		}
	}

private:
	int m_callId;
};


class LHttpRequest :public LRefObject<ZHttpRequest>
{
public:

	void ctor(LuaFuncState& L)
	{
		pThis = new ZRefCountedObject<ZHttpRequest>();
		LResponseCallback* callback = new ZRefCountedObject<LResponseCallback>(L.arg(0));
		pThis->setResponseCallback(callback, httpresponse_selector(LResponseCallback::OnResponce));
		pThis->AddRef();
	}

	int getType(LuaFuncState& L)
	{
		return L.lreturn(pThis->getRequestType());
	}

	int setType(LuaFuncState& L)
	{
		pThis->setRequestType((ZHttpRequest::Type)L.arg(0).toInt());
		return 0;
	}

	int setUrl(LuaFuncState& L)
	{
		pThis->setUrl(L.arg(0).toString());
		return 0;
	}

	int getUrl(LuaFuncState& L)
	{
		return L.lreturn(pThis->getUrl());
	}

	int setData(LuaFuncState& L)
	{
		pThis->setRequestData(L.arg(0).toString(),L.arg(0).objLen());
		return 0;
	}

	int getData(LuaFuncState& L)
	{
		return L.lreturn(pThis->getRequestData());
	}

	int setHeaders(LuaFuncState& L)
	{
		LuaTable lheaders = L.arg(0);
		if (!lheaders.isValid())
			return 0;

		std::vector<std::string> headers;
		for (LuaTable::Iterator i = lheaders.begin();i!= lheaders.end();++i)
		{
			headers.push_back(i.value().toString());
		}

		pThis->setHeaders(headers);
		return 0;
	}

	BEGIN_MAP_FUNC(LHttpRequest)
	DECLARE_FUNC(getType),
	DECLARE_FUNC(setType),
	DECLARE_FUNC(setUrl),
	DECLARE_FUNC(getUrl),
	DECLARE_FUNC(setData),
	DECLARE_FUNC(getData),
	DECLARE_FUNC(setHeaders),
	END_MAP_FUNC


	BEGIN_MAP_CONST
	DECLARE_CONST("POST", ZHttpRequest::TYPE_POST),
	DECLARE_CONST("GET", ZHttpRequest::TYPE_GET),
	DECLARE_CONST("PUT", ZHttpRequest::TYPE_PUT),
	DECLARE_CONST("DELETE", ZHttpRequest::TYPE_DELETE),
	END_MAP_CONST
};


class LHttpClient :public LuaClass<ZuiLib::ZHttpClient>
{
public:

	static this_t* instance()
	{
		return ZuiLib::ZHttpClient::getInstance();
	}

	int send(LuaFuncState& L)
	{
		ZHttpRequestPtr request = LuaClass<ZHttpRequest>::luaToC(L.arg(0));
		if(request)
			pThis->send(request);
		return 0;
	}

	int sendImmediate(LuaFuncState& L)
	{
		ZHttpRequestPtr request = LuaClass<ZHttpRequest>::luaToC(L.arg(0));
		if (request)
			pThis->sendImmediate(request);
		return 0;
	}

	int enableCookies(LuaFuncState& L)
	{
		pThis->enableCookies(L.arg(0).toString());
		return 0;
	}

	int setTimeoutForConnect(LuaFuncState& L)
	{
		pThis->setTimeoutForConnect(L.arg(0).toInt());
		return 0;
	}

	int getTimeoutForConnect(LuaFuncState& L)
	{
		return L.lreturn(pThis->getTimeoutForConnect());
	}

	int setTimeoutForRead(LuaFuncState& L)
	{
		pThis->setTimeoutForRead(L.arg(0).toInt());
		return 0;
	}

	int getTimeoutForRead(LuaFuncState& L)
	{
		return L.lreturn(pThis->getTimeoutForRead());
	}

	BEGIN_MAP_FUNC(LHttpClient)
		DECLARE_FUNC(send),
		DECLARE_FUNC(sendImmediate),
		DECLARE_FUNC(enableCookies),
		DECLARE_FUNC(setTimeoutForConnect),
		DECLARE_FUNC(getTimeoutForConnect),
		DECLARE_FUNC(setTimeoutForRead),
		DECLARE_FUNC(getTimeoutForRead),
	END_MAP_FUNC
};


}//namespace

